<template>
    <div id="dom1">
    </div>
</template>
<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
// 导入 GUI
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js"
// 导入 hdr 加载器
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader'
// 导入 gltf 加载器
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
// 压缩过的 gltf 用 DRACOLoader 解析器
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
// 导入 tween 补间动画
import * as TWEEN from 'three/examples/jsm/libs/tween.module.js';
// 导入 水面
import { Water } from "three/examples/jsm/objects/Water"
import gsap from "gsap"
export default {
    data() {
        return {
            screenWidth: document.innerWidth,
            guis: null,
        }
    },
    computed: {

    },
    methods: {
        // 创建三角形平面 最原生的
        fnNewGeometry() {
            const geometry = new THREE.BufferGeometry();
            // 创建顶点数据，顶点是有顺序的，逆时针为正面
            const vertices = new Float32Array([
                0.0, 0.0, -100.0, //顶点1
                50.0, 0.0, -100.0,//顶点2
                50.0, 50.0, -100.0,//顶点3
                0.0, 50.0, -100.0,//顶点4
            ])
            geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
            // 创建顶点属性
            const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
            // 创建索引 此时就会成正方形
            geometry.setIndex(new THREE.BufferAttribute(indices, 1))
            // 设置两个顶点组，形成2个材质
            geometry.addGroup(0, 3, 0); //参数 从0顶点开始添加3个顶点，用第一个材质
            geometry.addGroup(3, 3, 1);

            // 创建材质
            const material = new THREE.MeshBasicMaterial({
                color: 0x00ff00,
                side: THREE.DoubleSide,//双面都能看到
            })
            const material1 = new THREE.MeshBasicMaterial({
                color: 0xff0000,
                side: THREE.DoubleSide,//双面都能看到
            })

            return new THREE.Mesh(geometry, [material, material1]);
        },
        // 创建有材质的平面图形
        fnNewGeometryHaveImg() {
            // 创建纹理加载器
            let textureLoader = new THREE.TextureLoader();
            // 加载纹理
            let texture = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231017/file-cad6cc22-e018-4f9e-bd13-f289a84ce44f.png");
            texture.colorSpace = THREE.LinearSRGBColorSpace; //转换为线性srgb色 色差有问题使用这个
            // 加载AO贴图（环境遮挡贴图）
            let aoMap = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231017/file-cad6cc22-e018-4f9e-bd13-f289a84ce44f.png");
            // alpha贴图(透明度贴图) 黑色完全透明，白色完全不透明
            let alphaMap = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231017/file-cad6cc22-e018-4f9e-bd13-f289a84ce44f.png")
            // 光照贴图
            let lightMap = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231018/file-31fd3feb-4c47-429c-8b90-c06607192ec4.jpeg")
            // 高光贴图 白色反射 黑色不反射
            let specularMap = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231018/file-31fd3feb-4c47-429c-8b90-c06607192ec4.jpeg")

            let planeGeometry = new THREE.PlaneGeometry(100, 100)
            let planeMaterial = new THREE.MeshBasicMaterial({
                map: texture,
                aoMap: aoMap,
                // alphaMap: alphaMap,
                // lightMap: lightMap,
                // specularMap:specularMap,
                color: 0xffffff,
                side: THREE.DoubleSide,//双面都能看到
                transparent: true, //允许透明
                reflectivity: 0.8,//反射强度
            })
            //为改图片设置环境贴图反射 
            const rgbeLoader = new RGBELoader();
            rgbeLoader.loadAsync("./img/001.hdr").then((texture) => {
                //设置球形映射
                texture.mapping = THREE.EquirectangularReflectionMapping;
                //背景贴图
                planeMaterial.envMap = texture;
                //环境贴图
            });
            return new THREE.Mesh(planeGeometry, planeMaterial);
        },
        // 创建有材质的正方体
        fnNewMaterialCube() {
            let geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个几何对象
            // 创建纹理加载器
            let textureLoader = new THREE.TextureLoader();
            // 加载纹理
            let texture = textureLoader.load("http://81.68.222.174:3000/upload/keydata/0/20231018/file-9cc5dc5f-5f1a-41fd-917d-6d6045f58f0f.jpeg");
            texture.colorSpace = THREE.LinearSRGBColorSpace; //转换为线性srgb色 色差有问题使用这个
            let meterial = new THREE.MeshBasicMaterial({
                map: texture,
                color: 0xffffff,
                side: THREE.DoubleSide,//双面都能看到
                transparent: true, //允许透明
                reflectivity: 0.8,//反射强度
            })
            //为改图片设置环境贴图反射 
            const rgbeLoader = new RGBELoader();
            rgbeLoader.loadAsync("./img/001.hdr").then((texture) => {
                //设置球形映射
                texture.mapping = THREE.EquirectangularReflectionMapping;
                //背景贴图
                meterial.envMap = texture;
                //环境贴图
            });
            return new THREE.Mesh(geometry, meterial);

        },
        // 有材质的球体
        fnNewRedios(textureImg, radius) {
            const geometry = new THREE.SphereGeometry(radius, 32, 16);
            let textureLoader = new THREE.TextureLoader();
            let texture = textureLoader.load(textureImg);
            texture.colorSpace = THREE.LinearSRGBColorSpace; //转换为线性srgb色 色差有问题使用这个
            const material = new THREE.MeshBasicMaterial({ map: texture, });
            return new THREE.Mesh(geometry, material);

        },
        // hdr加载器
        fnRGBLoader(scene) {
            const rgbeLoader = new RGBELoader();
            rgbeLoader.loadAsync("./img/sky1.hdr").then((texture) => {
                //设置球形映射
                texture.mapping = THREE.EquirectangularReflectionMapping;
                //背景贴图
                scene.background = texture;
                //环境贴图
                scene.environment = texture;
            });
        },
        // TextureLoade 加载器
        fnTextureLoader(scene) {
            const textureLoader = new THREE.TextureLoader();
            textureLoader.loadAsync("./img/sky1.jpg").then((texture) => {
                //设置球形映射
                texture.mapping = THREE.EquirectangularReflectionMapping;
                //背景贴图
                scene.background = texture;
                //环境贴图
                scene.environment = texture;
            });
        },
        // 雾
        fnFog(scene) {
            // 线性雾
            // scene.fog = new THREE.Fog(0x999999,0.01,1000)
            //指数雾
            scene.fog = new THREE.FogExp2(0x999999, 0.1);
        },
        fnAddGui(cube, name) {
            this.guis = new GUI();
            // let guiParent = document.getElementById('dom1');
            this.guis.domElement.style.position = 'absolute';
            this.guis.domElement.style.zIndex = '5';
            this.guis.domElement.style.top = '145px';
            this.guis.domElement.style.right = '30px';
            // 添加按钮
            this.guis.add(this, "Fullscreen").name("全屏")
            this.guis.add(this, "ExitFullScreen").name("退出全屏");

        },
        fnCube1Gui(cube, name) {
            // 控制立方体 step 每次移动增加的数值
            let folder = this.guis.addFolder(`${name}参数`)
            folder.closed = true; // 设置文件夹的默认状态为折叠
            folder.add(cube.position, "x", -100, 500).step(10).name("立方体x轴位置")
            folder.add(cube.position, "y", -100, 500).step(10).name("立方体y轴位置").onFinishChange((val) => {
                console.log("拖动结束触发事件")
            })
            folder.add(cube.position, "z", -100, 500).step(10).name("立方体z轴位置").onChange(() => {
                console.log("拖动触发事件")
            })
            // guiParent.appendChild(this.guis.domElement);
        },
        fnCube3Gui(cube3, meterial2, name) {
            let folder = this.guis.addFolder(`${name}参数`)

            folder.add(meterial2, "wireframe").name("材质2线框")
            folder.addColor({
                cubeColor: "#0xaaff11"
            }, "cubeColor").name("立方体颜色").onChange((val) => {
                cube3.material.color.set(val)
            })
        },
        Fullscreen() {
            console.log("__123_")
            document.body.requestFullscreen()
        },
        ExitFullScreen() {
            document.exitFullscreen();
        },
        // 主函数
        fnTreeUse() {
            let width = window.innerWidth; //窗口宽度
            let height = window.innerHeight; //窗口高度RGBELoader
            let k = width / height; //窗口宽高比
            let s = 400; //三维场景显示范围控制系数，系数越大，显示的范围越大
            let DOM = document.getElementById("dom1");

            // 创建画布
            const scene = new THREE.Scene();
            const renderer = new THREE.WebGLRenderer(
                {
                    antialias: true, // 设置抗锯齿

                }
            );
            renderer.setSize(width, height);
            // 画布全景背景加载
            this.fnTextureLoader(scene)

            // 建模加载器实例化
            // 初始化解压模型
            const gltfLoad = new GLTFLoader();
            gltfLoad.load(
                "./model/002.glb",
                // 加载建模完的回调函数
                (gltf) => {
                    console.log("____gltf,", gltf)
                    let cubeGlb = gltf.scene;
                    cubeGlb.position.set(0, 0, 0);
                    gltf.scene.traverse((child) => {
                        if (child.isMesh) {
                            // 修改材质属性
                            // 其他修改材质的操作...
                            if (child.name === "plane") {
                                child.visible = false;
                            }
                            // 允许接受投射阴影
                            if (child.isMesh) {
                                child.castShadow = true;
                                child.receiveShadow = true;
                            }
                        }
                    });
                    scene.add(cubeGlb)
                }
            )
            // 设置调色映射
            renderer.toneMapping = THREE.ACESFilmicToneMapping;
            renderer.toneMappingExposure = 0.5;
            renderer.shadowMap.enabled = true;  // 启用阴影
            renderer.shadowMap.type = THREE.PCFSoftShadowMap;  // 阴影质量
            renderer.physicallyCorrectLights = true;
            // 设置水面效果
            const waterGeometry = new THREE.PlaneGeometry(300, 300);
            let water = new Water(waterGeometry, {
                textureWidth: 512,
                textureHeight: 512,
                // 纹理图片
                waterNormals: new THREE.TextureLoader().load(
                    "img/water.png",
                    function (texture) {
                        texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
                    }
                ),
                sunDirection: new THREE.Vector3(),
                sunColor: 0xffffff,
                waterColor: 0x001e0f,
                distortionScale: 3.7,
                alpha: 1.0,
                flowDirection: new THREE.Vector2(1, 0), // 水体流动方向为x轴正方向
                fog: scene.fog !== undefined,
            });
            water.rotation.x = -Math.PI / 2;
            water.position.set(0, -0.4, 0);
            scene.add(water)


            //添加平行光
            const light = new THREE.DirectionalLight(0xffffff, 1);
            light.position.set(0, 50, 0);
            scene.add(light)
            // 添加点光源
            const pointLight = new THREE.PointLight(0xffffff, 50);
            pointLight.position.set(0.5, 2.3, 0);
            pointLight.castShadow = true;
            pointLight.shadow.mapSize.width = 1024;  // 阴影贴图宽度
            pointLight.shadow.mapSize.height = 1024; // 阴影贴图高度
            pointLight.shadow.camera.near = 0.5;     // 阴影相机近平面
            pointLight.shadow.camera.far = 50;       // 阴影相机远平面
            scene.add(pointLight);
            // 添加点光源组
            const pointLightGroup = new THREE.Group();
            pointLightGroup.position.set(-8, 2.5, -1.5);
            let radius = 3;
            let pointLightArr = [];
            for (let i = 0; i < 3; i++) {
                // 创建球体 当灯泡
                const shaperGeometory = new THREE.SphereGeometry(0.2, 32, 32);
                const sphereMaterial = new THREE.MeshStandardMaterial({
                    color: 0xffffff,
                    emissive: 0xffffff,
                    emissiveIntersity: 10,
                });
                const sphere = new THREE.Mesh(shaperGeometory, sphereMaterial);
                pointLightArr.push(sphere);
                sphere.position.set(
                    radius * Math.cos((i * 2 * Math.PI) / 3),
                    Math.cos((i * 2 * Math.PI) / 3),
                    radius * Math.sin((i * 2 * Math.PI) / 3),
                );
                let pointLight2 = new THREE.PointLight(0xffffff, 10);
                sphere.add(pointLight2);
                pointLightGroup.add(sphere);

            }
            scene.add(pointLightGroup);
            // 补间动画 从 0 到 2Π
            let options = {
                angle: 0,
            };
            gsap.to(options, {
                angle: Math.PI * 2,
                duration: 10,
                repeat: -1,
                ease: "linear",
                onUpdate: () => {
                    pointLightGroup.rotation.y = options.angle;
                    pointLightArr.forEach((item, index) => {
                        item.position.set(
                            radius * Math.cos((index * 2 * Math.PI) / 3),
                            Math.cos((index * 2 * Math.PI) / 3 + options.angle * 5),
                            radius * Math.sin((index * 2 * Math.PI) / 3),
                        )
                    })
                }
            })
            //环境光
            // let ambient = new THREE.AmbientLight(0xffffff, 0.5);
            // scene.add(ambient);

            // 相机位置
            const camera = new THREE.PerspectiveCamera(45, k, 0.1, 10000);
            camera.position.set(-30, 30, 40); //设置相机位置
            camera.lookAt(scene.position); //设置相机方向(指向的场景对象)

            // 添加坐标系
            // const axesHelper = new THREE.AxesHelper(500);
            // scene.add(axesHelper);
            // 添加局部坐标系
            // const axesHelperCube = new THREE.AxesHelper(150);

            // 添加控制器
            const controls = new OrbitControls(camera, DOM);
            controls.enableDamping = true; //带阻尼
            controls.dampingFactor = 0.08;//阻尼系数，越小越滑
            // controls.autoRotate = true;//相机自动旋转（坐标系也转动）

            // 补间动画
            // const sunTween = new TWEEN.Tween(sun.position);
            // sunTween.to({x:200},10000);
            // sunTween.repeat(Infinity);//循环无数次
            // sunTween.yoyo(true);//循环往复
            // sunTween.delay(3000);//每次运行等待3s 延迟操作   
            // sunTween.start();
            // Dom添加
            DOM.appendChild(renderer.domElement);
            // 渲染场景
            function fnAnimate(time) {
                controls.update();
                // 更新补间动画
                // 更新水面着色器中的时间变量
                water.material.uniforms["time"].value += 0.1 / 60.0;

                // sunTween.update();
                renderer.render(scene, camera)
                requestAnimationFrame(fnAnimate);
            }
            fnAnimate()

            // renderer.render(scene, camera)

            // 监听事件，监听页面变化并更新视图
            window.addEventListener("resize", () => {
                renderer.setSize(window.innerWidth, window.innerHeight);//重置渲染器宽高比
                camera.aspect = window.innerWidth / window.innerHeight; //重置相机位置
                camera.updateProjectionMatrix();//更新
            })
        }
    },
    mounted() {
        this.$nextTick(() => {
            this.fnTreeUse()
        })
        // 声明GUI操作面板



        // const that = this;
        // window.onresize = () => (() => {
        //     that.screenWidth = window.innerWidth;
        // })();

    },
    watch: {
        // screenWidth(newVal, oldVal) {
        //     if(newVal){

        //     }
        // }
    }
}
</script>
<style scoped lang="less">
* {
    margin: 0;
    padding: 0;
}

.dom1 {
    width: 100%;
    height: 100%;
}

canvas {
    display: block;
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
}
</style>